﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Diagnostics;


namespace ScreenShark
{
    public class SharkApp
    {
        private const String RegKey = @"Software\Microsoft\Windows\CurrentVersion\Run";

        private static readonly SharkApp _Instance = new SharkApp();

        private List<ImageCodecInfo> fCodecs;


        public static SharkApp Instance
        {
            get
            {
                return _Instance;
            }
        }

        private SharkApp()
        {
            Initialize();
        }

        public static void OpenFileWith(String appPath, String filePath)
        {
            Process.Start(appPath, "\""+ filePath+"\"");
        }

        public static bool IsEncoderSupported(ImageCodecInfo codec, System.Drawing.Imaging.Encoder encoder)
        {
            var b = new Bitmap(1, 1);

            try
            {
                var epl = b.GetEncoderParameterList(codec.Clsid);

                var encParams = epl.Param;

                foreach (var e in encParams)
                {
                    if (e.Encoder.Guid == encoder.Guid)
                        return true;
                }
            }
            catch (NotImplementedException ex)
            {

            }
            finally
            {
                b.Dispose();
            }

            return false;
        }

        public static void GoToFileInExplorer(String path)
        {
            Process.Start("explorer.exe", @"/select, " + path);
        }

        public static void GoToDirectoryInExplorer(String path)
        {
            Process.Start("explorer.exe", @"/root, " + path);
        }

        public static Rectangle CalculateRectangle(CaptureMethod method)
        {
            Rectangle r = Rectangle.Empty;

            switch (method)
            {
                case CaptureMethod.AllScreens:
                    {
                        r = Monitor.CalculateCompleteBounds();
                    }
                    break;
                case CaptureMethod.PrimaryScreen:
                    {
                        r = Monitor.PrimaryMonitor.GetMonitorInfo().Bounds;
                    }
                    break;
                case CaptureMethod.MouseHoveredScreen:
                    {
                        r = Monitor.FromPoint(Control.MousePosition).GetMonitorInfo().Bounds;
                    }
                    break;
            }

            return r;
        }

        
        public static string MsPaintPath
        {
            get
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "mspaint.exe");
            }
        }

        public static String SharkDocumentsPath
        {
            get
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Application.ProductName);
            }
        }

        
        public String LastScreenshot
        {
            get;
            private set;
        }

        public String OutputDirectory
        {
            get;
            set;
        }

        public ImageCodecInfo CodecInfo
        {
            get;
            set;
        }

        public CaptureMethod CaptureMethod { get; set; }
        public PostCaptureAction PostCaptureAction { get; set; }
        public string OpenWith { get; set; }
        public bool RunOnStartup { get; set; }
        public bool PreviewBeforeSave { get; set; }
        public int JpegQuality { get; set; }

        public IEnumerable<ImageCodecInfo> Codecs
        {
            get
            {
                if (null == fCodecs)
                {
                    fCodecs = new List<ImageCodecInfo>();
                    fCodecs.AddRange(ImageCodecInfo.GetImageEncoders());
                }

                return fCodecs;
            }
        }

        public static string GetNewFileName()
        {
            return DateTime.Now.Ticks.ToString();            
        }

        public void GoToLastScreenshot()
        {
            if (String.IsNullOrEmpty(LastScreenshot) || !File.Exists(LastScreenshot))
                GoToOutputDirectory();
            else
                GoToFileInExplorer(LastScreenshot);
        }

        public void GoToOutputDirectory()
        {
            GoToDirectoryInExplorer(OutputDirectory);
        }

        public Image CaptureScreenshot(bool activeWindowOnly)
        {
            return activeWindowOnly ? Screenshot.CaptureActiveWindow() : Screenshot.CaptureRectangle(CalculateRectangle(CaptureMethod));
        }       

        public void DoPostCaptureAction()
        {
            switch (PostCaptureAction)
            {
                case PostCaptureAction.DoNothing:
                    return;
                case PostCaptureAction.GoToLastScreenshot:
                    GoToLastScreenshot();
                    return;
                case PostCaptureAction.OpenWith:
                    OpenFileWith(OpenWith, LastScreenshot);
                    return;
            }
        }

        public void SaveImageToOutputDirectory(Image image,String fileName)
        {
            if (String.IsNullOrEmpty(OutputDirectory))
            {
                throw new InvalidOperationException("Path not specified!");
            }

            if (!Directory.Exists(OutputDirectory))
            {
                Directory.CreateDirectory(OutputDirectory);
            }

            var ext = CodecInfo.FilenameExtension.Split(';')[0].ToLower();
            if (ext.StartsWith("*"))
                ext = ext.Remove(0, 1);

            var fullPath = Path.Combine(OutputDirectory, fileName + ext);

            image.Save(fullPath, CodecInfo, GetEncoderParameters());

            LastScreenshot = fullPath;
        }

        public EncoderParameters GetEncoderParameters()
        {
            List<EncoderParameter> paramList = new List<EncoderParameter>();

            if (IsEncoderSupported(CodecInfo, System.Drawing.Imaging.Encoder.Quality))
            {
                paramList.Add(new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, JpegQuality));
            }

            if (0 == paramList.Count) return null;

            EncoderParameters e = new EncoderParameters(paramList.Count);
            
            for (int i = 0; i < paramList.Count; i++)
            {
                e.Param[i] = paramList[i];
            }

            return e;
        }

        public void LoadSettings()
        {
            var s = Properties.Settings.Default;

            OutputDirectory = s.Directory;
            CodecInfo = GetCodecInfo(s.ImageFormat);
            CaptureMethod = s.CaptureMethod;
            PostCaptureAction = s.PostCaptureAction;
            OpenWith = s.OpenWith;
            PreviewBeforeSave = s.PreviewBeforeSave;
            JpegQuality = s.JpegQuality;
        }

        public ImageCodecInfo GetCodecInfo(Guid id)
        {
            foreach (var c in Codecs)
            {
                if (c.FormatID.Equals(id))
                    return c;
            }

            return null;
        }

        public void SaveSettings()
        {
            // settings
            var s = Properties.Settings.Default;
            s.Directory = OutputDirectory;
            s.ImageFormat = CodecInfo.FormatID;
            s.CaptureMethod = CaptureMethod;
            s.PostCaptureAction = PostCaptureAction;
            s.OpenWith = OpenWith;
            s.PreviewBeforeSave = PreviewBeforeSave;
            s.JpegQuality = JpegQuality;

            s.Save();
            
            // registry
            var key = Registry.LocalMachine.OpenSubKey(RegKey, true);

            if (!RunOnStartup)
                key.DeleteValue(Application.ProductName,false);
            else
                key.SetValue(Application.ProductName,Application.ExecutablePath,RegistryValueKind.String);

            key.Close();
        }


        private void PrepareSettings()
        {
            var s = Properties.Settings.Default;

            if (String.IsNullOrEmpty(s.Directory))
                s.Directory = SharkDocumentsPath;

            if (String.IsNullOrEmpty(s.OpenWith))
                s.OpenWith = MsPaintPath;

            if (Guid.Empty == s.ImageFormat)
                s.ImageFormat = ImageFormat.Bmp.Guid;
        }

        private void Initialize()
        {
            PrepareSettings();

            // registry
            var key = Registry.LocalMachine.OpenSubKey(RegKey, true);

            String result = (String)key.GetValue(Application.ProductName, String.Empty);

            RunOnStartup = Path.Equals(result, Application.ExecutablePath);

            key.Close();

            // registry
        }
    }
}
